﻿using Microsoft.Win32;
using SymulatorEthernetWPF.Shared;
using SymulatorEthernetWPF.SimObjects;
using SymulatorEthernetWPF.SimObjects.Devices;
using SymulatorEthernetWPF.SimObjects.Wires;
using SymulatorEthernetWPF.UserInterface.UIElements;
using System;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Management;
using System.Runtime.Serialization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace SymulatorEthernetWPF.UserInterface
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            Size? windowSize = LoadWindowSize();
            Point? windowPosition = LoadWindowPosition();
            bool isMaximized = LoadIsWindowMaximized();
            var cpus = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_Processor");
            

            if (isMaximized)
            {
                WindowState = WindowState.Maximized;
                return;
            }
            if (windowSize != null)
            {
                Height = windowSize.Value.Height;
                Width = windowSize.Value.Width;
            }
            if (windowPosition != null)
            {
                Left = windowPosition.Value.X;
                Top = windowPosition.Value.Y;
            }
        }

        private void MainMenuZakonczClick(object sender, RoutedEventArgs e)
        {
            Close();
        }

        private void AddHostButtonClick(object sender, RoutedEventArgs e)
        {
            Simulation.UndoStack.Push(new HistoryElement());
            Simulation.RedoStack.Clear();
            Simulation.simObjects.Add(new HostControl());
        }

        private void AddSwitchButtonClick(object sender, RoutedEventArgs e)
        {
            Simulation.UndoStack.Push(new HistoryElement());
            Simulation.RedoStack.Clear();
            Simulation.simObjects.Add(new SwitchControl());
        }

        private void AddHubButtonClick(object sender, RoutedEventArgs e)
        {
            Simulation.UndoStack.Push(new HistoryElement());
            Simulation.RedoStack.Clear();
            Simulation.simObjects.Add(new HubControl());
        }

        private void WindowClosing(object sender, CancelEventArgs e)
        {
            SaveIsWindowsMaximized((WindowState == WindowState.Maximized));
            SaveWindowPosition(new Point(Left, Top));
            SaveWindowSize(new Size(Width, Height));
        }

        private void NewSimButtonClick(object sender, RoutedEventArgs e)
        {
            
            StaticVars.TmpWire = null;
            Simulation.reset();
            GC.Collect();

        }

        private static Size? LoadWindowSize()
        {
            RegistryKey reg = Registry.CurrentUser;
            try
            {
                reg = reg.OpenSubKey("SOFTWARE\\SymulatorEthernet");
                if (reg != null)
                {
                    int height = Int32.Parse(reg.GetValue("Height").ToString());
                    int width = Int32.Parse(reg.GetValue("Width").ToString());
                    return new Size(width, height);
                }
                return null;
            }
            catch
            {
                return null;
            }
        }

        private static Point? LoadWindowPosition()
        {
            RegistryKey reg = Registry.CurrentUser;
            try
            {
                reg = reg.OpenSubKey("SOFTWARE\\SymulatorEthernet");
                if (reg != null)
                {
                    int x = Int32.Parse(reg.GetValue("X").ToString());
                    int y = Int32.Parse(reg.GetValue("Y").ToString());
                    return new Point(x, y);
                }
                return null;
            }
            catch
            {
                return null;
            }
        }

        private static bool LoadIsWindowMaximized()
        {
            RegistryKey reg = Registry.CurrentUser;
            try
            {
                reg = reg.OpenSubKey("SOFTWARE\\SymulatorEthernet");
                return reg != null && Boolean.Parse(reg.GetValue("Maximized").ToString());
            }
            catch
            {
                return false;
            }
        }

        private static  void SaveWindowSize(Size size)
        {
            RegistryKey reg = Registry.CurrentUser;
            reg = reg.CreateSubKey("SOFTWARE\\SymulatorEthernet");
            if (reg != null)
            {
                reg.SetValue("Height", size.Height);
                reg.SetValue("Width", size.Width);
            }
        }

        private static void SaveWindowPosition(Point position)
        {
            RegistryKey reg = Registry.CurrentUser;
            reg = reg.CreateSubKey("SOFTWARE\\SymulatorEthernet");
            if (reg != null)
            {
                reg.SetValue("X", position.X);
                reg.SetValue("Y", position.Y);
            }
        }

        private static void SaveIsWindowsMaximized(bool isMaximized)
        {
            RegistryKey reg = Registry.CurrentUser;

            reg = reg.CreateSubKey("SOFTWARE\\SymulatorEthernet");
            if (reg != null) reg.SetValue("Maximized", isMaximized);

        }

        private void MainMenuAboutClick(object sender, RoutedEventArgs e)
        {
            (new About()).ShowDialog();
        }

        private void WindowKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Escape && StaticVars.IsSettingUpWire)
            {
                StaticVars.IsSettingUpWire = false;
                StaticVars.TmpWire.DeleteWire();
                StaticVars.TmpWire = null;
            }
            if (e.Key == Key.Delete && !StaticVars.IsSettingUpWire)
            {
                try
                {
                    foreach (UIElement it in Simulation.simObjects)
                    {
                        if (it is DeviceControl)
                        {
                            if (((DeviceControl)it).IsSelected())
                                ((DeviceControl)it).delete();
                        }
                    }
                }
                catch { }
            }
        }

        private void WindowLoaded(object sender, RoutedEventArgs e)
        {
            StaticVars.MainWindow = this;

            InfoBar.deviceControl = null;

            scaleSlider.ToolTip = "Skala: 100%";
        }

        private void StartSimButtonClick(object sender, RoutedEventArgs e)
        {
            Simulation.startSim();
        }

        private void PauseSimButtonClick(object sender, RoutedEventArgs e)
        {
            Simulation.pauseSim();
        }

        private void StopSimButtonClick(object sender, RoutedEventArgs e)
        {
            Simulation.stopSim();
        }

        private void ScaleSliderValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            try
            {
                customCanvas.RenderTransform = new ScaleTransform(scaleSlider.Value, scaleSlider.Value);
                StaticVars.CanvasScale = scaleSlider.Value;
                scaleSlider.ToolTip = "Skala: " + (Math.Ceiling(scaleSlider.Value*100)).ToString(CultureInfo.InvariantCulture) + "%";
                statusLabel.ShowMessage(scaleSlider.ToolTip.ToString(), true);
                customCanvas.DoLogic();
            }
            catch
            {
            }
        }

        public void ScrollViewerMouseWheel(object sender, MouseWheelEventArgs e)
        {
            if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
            {
                if (e.Delta > 0 && scaleSlider.Value < 2)
                {
                    scaleSlider.Value += 0.1;
                }
                else if (e.Delta < 0 && scaleSlider.Value > 0.2)
                {
                    scaleSlider.Value -= 0.1;
                }
            }

            else if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
            {
                if (e.Delta > 0)
                {
                    scrollViewer.ScrollToHorizontalOffset(scrollViewer.HorizontalOffset - 10);
                }
                else if (e.Delta < 0)
                {
                    scrollViewer.ScrollToHorizontalOffset(scrollViewer.HorizontalOffset + 10);
                }
            }
            else
            {
                if (e.Delta > 0)
                {
                    scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - 10);
                }
                else if (e.Delta < 0)
                {
                    scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + 10);
                }
            }
        }

        private void ScaleSliderMouseWheel(object sender, MouseWheelEventArgs e)
        {
            if (e.Delta > 0 && scaleSlider.Value < 2)
            {
                scaleSlider.Value += 0.1;
            }
            else if (e.Delta < 0 && scaleSlider.Value > 0.2)
            {
                scaleSlider.Value -= 0.1;
            }
        }

        private void UndoButtonClick(object sender, RoutedEventArgs e)
        {
            Simulation.RedoStack.Push(new HistoryElement());
            Simulation.simObjects.Clear();
            HistoryElement he = Simulation.UndoStack.Pop();
            foreach (ISerializable it in he.Controls)
            {
                if (it is UIElement)
                {
                    customCanvas.Children.Add((UIElement)it);
                    if (it is Wire)
                        ((Wire)it).updateWire();
                }
            }
            Simulation.taskQueue.Clear();
            foreach (TaskQueueItem it in he.TaskQueueItems)
            {
                Simulation.taskQueue.Add(it);
            }
        }

        private void RedoButtonClick(object sender, RoutedEventArgs e)
        {
            Simulation.UndoStack.Push(new HistoryElement());
            Simulation.simObjects.Clear();
            HistoryElement he = Simulation.RedoStack.Pop();
            foreach (ISerializable it in he.Controls)
            {
                if (it is UIElement)
                {
                    customCanvas.Children.Add((UIElement)it);
                    if (it is Wire)
                        ((Wire)it).updateWire();
                }
            }
            Simulation.taskQueue.Clear();
            foreach (TaskQueueItem it in he.TaskQueueItems)
            {
                Simulation.taskQueue.Add(it);
            }

        }

        private void ButtonHover(object sender, MouseEventArgs e)
        {
            if (sender.GetType() == typeof (Button))
                statusLabel.ShowMessage(((Button) sender).ToolTip.ToString());
            else if (sender.GetType() == typeof (Slider))
                statusLabel.ShowMessage(((Slider) sender).ToolTip.ToString());
        }

        private void ButtonLeave(object sender, MouseEventArgs e)
        {
            statusLabel.FadeOut();
        }

        private void SaveSimClick(object sender, RoutedEventArgs e)
        {
            var dlg = new SaveFileDialog
                          {FileName = "Symulacja", DefaultExt = ".es1", Filter = "Plik symulacji (.es1)|*.es1"};

            bool? result = dlg.ShowDialog();

            // Process save file dialog box results
            if (result == true)
            {
                StaticVars.IsSaveLoad = true;
                try
                {
                    statusLabel.ShowMessage("Zapisywanie");
                    FileStream fs = File.OpenWrite(dlg.FileName);
                    var toSave = new HistoryElement();
                    byte[] toSaveArray = toSave.GetMemoryStream().ToArray();
                    byte[] toSaveArrayCompressed = StaticFunctions.Compress(toSaveArray);
                    fs.Write(toSaveArrayCompressed, 0, toSaveArrayCompressed.Length);
                    fs.Close();
                    statusLabel.FadeOut();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
                finally
                {
                    StaticVars.IsSaveLoad = false;
                    IsEnabled = true;
                }
            }
        }

        private void OpenSimClick(object sender, RoutedEventArgs e)
        {
            var dlg = new OpenFileDialog
                          {FileName = "Symulacja", DefaultExt = ".es1", Filter = "Plik symulacji (.es1)|*.es1"};

            bool? result = dlg.ShowDialog();
            if (result == true)
            {
                StaticVars.IsSaveLoad = true;
                try
                {
                    FileStream fs = File.OpenRead(dlg.FileName);
                    var toLoadArray = new byte[fs.Length];
                    fs.Read(toLoadArray, 0, (int) fs.Length);
                    fs.Close();
                    byte[] toLoadArrayDecompressed = StaticFunctions.Decompress(toLoadArray);
                    var toLoad = new HistoryElement(toLoadArrayDecompressed);
                    customCanvas.Children.Clear();
                    Simulation.reset();
                    foreach (ISerializable it in toLoad.Controls)
                    {
                        if (it is UIElement)
                        {
                            customCanvas.Children.Add((UIElement)it);
                            if (it.GetType() == typeof(HostControl))
                                Simulation.HostCounter++;
                            else if (it.GetType() == typeof(HubControl))
                                Simulation.HubCounter++;
                            else if (it.GetType() == typeof(SwitchControl))
                                Simulation.SwitchCounter++;
                            if (it is Wire)
                                ((Wire)it).updateWire();
                        }
                    }
                    foreach (TaskQueueItem it in toLoad.TaskQueueItems)
                    {
                        Simulation.taskQueue.Add(it);
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
                finally
                {
                    StaticVars.IsSaveLoad = false;
                }
            }
        }

        private void ExportClick(object sender, RoutedEventArgs e)
        {
            var dlg = new SaveFileDialog { FileName = "eksport", DefaultExt = ".png", Filter = "Plik obrazu (.png)|*.png" };

            bool? result = dlg.ShowDialog();

            if (result == true)
            {
                Transform transform = customCanvas.LayoutTransform;
                customCanvas.LayoutTransform = null;
                Size size = new Size(customCanvas.Width, customCanvas.Height);
                customCanvas.Measure(size);
                customCanvas.Arrange(new Rect(size));
                RenderTargetBitmap renderBitmap = new RenderTargetBitmap((int)size.Width, (int)size.Height, 96d, 96d, PixelFormats.Pbgra32);
                renderBitmap.Render(customCanvas);
                using (FileStream outStream = new FileStream(dlg.FileName, FileMode.Create))
                {
                    PngBitmapEncoder encoder = new PngBitmapEncoder();
                    encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
                    encoder.Save(outStream);
                }

                customCanvas.LayoutTransform = transform;
            }
        }

        private void zoomInButton_Click(object sender, RoutedEventArgs e)
        {
            scaleSlider.Value += 0.1;
        }

        private void zoomOutButton_Click(object sender, RoutedEventArgs e)
        {
            scaleSlider.Value -= 0.1;
        }
    }
}